﻿using System.Collections.Concurrent;
using System.Net;
using System;
using System.Linq;
using System.Net.Sockets;
using System.Threading;
using Skybot.Extension;
using Skybot.Base.Pool;

namespace Skybot.Base.Mulitply
{
    /// <summary>
    /// 多线程数据处理服务默认4线程
    /// </summary>
    public class MultiplyGenericHelper<T>
    {
        /// <summary>
        /// 发送线程数
        /// </summary>
        public int OperationThreadNumber { get; private set; }

        #region 构造函数
        /// <summary>
        /// 创建一个新的多线程处理处理功能对像
        /// </summary>
        /// <param name="threadNumber">线程数,跟据CPU个数指定,最好不要超过8个</param>
        public MultiplyGenericHelper(int threadNumber = 4)
        {
            OperationThreadNumber = threadNumber;
        }
        #endregion

        #region 多线程实时数据推送

        //初始化4线程
        internal ConcurrentDictionary<int, RealRecordTask<OperationRecord<T>>> TaskDic;

        /// <summary>
        /// 创建一个用于写入的数据对像
        /// </summary>
        /// <param name="index">对应的索引</param>
        /// <returns></returns>
        protected RealRecordTask<OperationRecord<T>> RecordBufferCreate(int index)
        {
            RealRecordTask<OperationRecord<T>> real;
            lock (TaskDic)
            {
                real = new RealRecordTask<OperationRecord<T>>
                           {
                               TagName = index.ToString(),
                               Splict = index,
                           };
                real.Task = new TaskEx(CycleOperation, real, new CancellationTokenSource()) { AutoReRun = true };

                if (TaskDic.TryAdd(index, real))
                {
                    //开始发送线程
                    real.Task.Start();
                    //添加到线程管理
                    ThreadManager.Instance.Add(real.Task);
                }
            }
            return real;
        }

        /// <summary>
        /// 循环处理发送实时数据
        /// 过程中包括.
        /// </summary>
        /// <param name="o">实时数据推送集合.</param>
        protected void CycleOperation(object o)
        {
            var task = (RealRecordTask<OperationRecord<T>>)o;
            while (IsWorking)
            {
                CycleOperationToClient(task.Queuedata);
            }
        }

        /// <summary>
        /// 循环发送到客户端
        /// </summary>
        /// <param name="queue">队列数据</param>
        protected void CycleOperationToClient(ConcurrentQueue<OperationRecord<T>> queue)
        {
            OperationRecord<T> pop = null;
            try
            {
                queue.TryDequeue(out pop);
                if (pop == null)
                {
                    Thread.Sleep(50);
                    return;
                }
                if (pop.ProtocolType == ProtocolType.Tcp)
                {
                    //发送数据到终端
                    if (pop.SocketHandler != null && pop.SocketHandler.Connected)
                    {
                        //发送数据
                        OperationHandler(pop.Operationbuffer, pop.SocketHandler, pop.EndPoint);
                    }
                }
                if (pop.ProtocolType == ProtocolType.Udp)
                {
                    //发送数据到终端
                    if (pop.SocketHandler != null)
                    {
                        //发送数据
                        OperationHandler(pop.Operationbuffer, pop.SocketHandler, pop.EndPoint);
                    }
                }
                #region 性能记数
                //处理速度
                System.Threading.Interlocked.Increment(ref  processingCount);
                #endregion
            }
            finally
            {
                if (pop != null)
                {
                    pop.ProtocolType = ProtocolType.Unknown;
                    pop.Operationbuffer = default(T);
                    pop.EndPoint = null;
                    pop.SocketHandler = null;
                    //还池
                    Pool.GaveBack(pop);
                }
            }
        }

        #endregion

        /// <summary>
        /// 发送数据处理方法
        /// </summary>
        public Func<T, Socket, EndPoint, bool> OperationHandler { get; set; }

        /// <summary>
        /// 开始 创建一个新的专用于多线程的数据发送功能
        /// 开始初始化线程
        /// </summary>
        public void Start()
        {
            //防止多次调用
            LazyInitializer.EnsureInitialized(ref TaskDic, () =>
                                                               {
                                                                   //设置为可以运行
                                                                   IsWorking = true;
                                                                   TaskDic = new ConcurrentDictionary<int, RealRecordTask<OperationRecord<T>>>(OperationThreadNumber, OperationThreadNumber);
                                                                   //初始4个实时数据发送线程
                                                                   Enumerable.Range(0, OperationThreadNumber).ToList().ForEach(index => RecordBufferCreate(index));
                                                                   return TaskDic;
                                                               });
        }

        /// <summary>
        /// 将当前获取的buff存放到写入队列当中
        /// </summary>
        /// <param name="identificationCode">标识码</param>
        /// <param name="socketHandler">远程节点</param>
        /// <param name="ep">远程终节点</param>
        /// <param name="OperationObj">需要处理的数据</param>
        /// <param name="protocolType"> 协议类型,默认TCP</param>
        public void Push(string identificationCode, Socket socketHandler, EndPoint ep, T OperationObj, ProtocolType protocolType = ProtocolType.Tcp)
        {
            if (identificationCode == null)
            {
                LogProvider.Create().Write(EventType.Error, string.Format("发生一个已处理的异常,{0}.Push方法;参数{1}不能为null", GetType().Name, "string identificationCode"));
                return;
            }
            //从池中取出一个数据
            var pop = Pool.Pop();

            //给数据传值
            pop.Operationbuffer = OperationObj;
            pop.SocketHandler = socketHandler;
            pop.EndPoint = ep;
            pop.ProtocolType = protocolType;

            //终端号
            int terminalcode = Math.Abs(identificationCode.GetHashCode());
            //跟据终端号分配线程
            int index = (terminalcode % TaskDic.Count);
            //每一个节点一个线程
            RealRecordTask<OperationRecord<T>> recordWrite = TaskDic[index];
            //添加数据
            lock (recordWrite.Queuedata)
            {
                recordWrite.Queuedata.Enqueue(pop);
            }
            #region 性能记数
            //添加速度
            System.Threading.Interlocked.Increment(ref  pushCount);
            #endregion
        }

        #region 池

        /// <summary>
        /// 中转对像数据池
        /// </summary>
        private BasePool<OperationRecord<T>> pool = new BasePool<OperationRecord<T>>(100, 20 * 10000, false);
        /// <summary>
        /// 中转对像数据池
        /// </summary>
        public BasePool<OperationRecord<T>> Pool
        {
            get { return pool; }
        }
        #endregion

        /// <summary>
        /// 是否可以运行
        /// </summary>
        public bool IsWorking { get; set; }

        #region 性能记数与统计信息

        /// <summary>
        /// 1.添加总个数
        /// </summary>
        long pushCount;
        /// <summary>
        /// 2.处理总个数
        /// </summary>
        long processingCount;
        /// <summary>
        /// 4.等待处理的数据
        /// </summary>
        public long WaitProcess
        {
            get
            {
                if (TaskDic != null)
                {
                    return TaskDic.Sum(p => p.Value.Queuedata.Count);
                }
                return 0;
            }
        }
        /// <summary>
        /// 1.添加总个数
        /// </summary>
        public long PushCount
        {
            get { return pushCount; }
        }
        /// <summary>
        /// 2.处理总个数
        /// </summary>
        public long ProcessingCount
        {
            get { return processingCount; }
        }
        #endregion
    }

    #region 使用池减少内存开消
    /// <summary>
    /// 池对像
    /// </summary>
    public class OperationRecord<T>
    {
        /// <summary>
        /// 需要发送到的节点
        /// </summary>
        public Socket SocketHandler { get; set; }
        /// <summary>
        /// TCP 或者UDP时的远程终节点
        /// </summary>
        public EndPoint EndPoint { get; set; }
        /// <summary>
        /// 需要发送的数据
        /// </summary>
        public T Operationbuffer { get; set; }
        /// <summary>
        /// 消息类型 Tcp,UDp
        /// </summary>
        public ProtocolType ProtocolType { get; set; }
    }
    #endregion
}
